
#include "doc_manager.h"

DocManager::DocManager()
{}

DocManager::~DocManager()
{
    sqlite3_finalize(getDocID_);
    sqlite3_finalize(insertDoc_);
    sqlite3_finalize(updateDoc_);
    sqlite3_finalize(getTitle_);
    sqlite3_finalize(getBody_);
    sqlite3_finalize(getDocCount_);
    sqlite3_close(db_);
}

int DocManager::LoadDB(std::string &db)
{
    dbPath_ = db;

    int ret = sqlite3_open(dbPath_.c_str(), &db_);
    if (ret != SQLITE_OK) {
        std::cout << "open " << db << " fail\n";
        return -1;
    }

    sqlite3_exec(db_,
            "CREATE TABLE IF NOT EXISTS documents (" \
            "id     INTEGER PRIMARY KEY NOT NULL," \
            "title	TEXT                NOT NULL UNIQUE," \
            "body	TEXT                NOT NULL" \
            ");",
            NULL, NULL, NULL);

    sqlite3_prepare(db_, "SELECT id FROM documents WHERE title = ?;", -1, &getDocID_, NULL);
    sqlite3_prepare(db_, "INSERT INTO documents (title, body) VALUES (?, ?);", -1, &insertDoc_, NULL);
    sqlite3_prepare(db_, "UPDATE documents set body = ? WHERE id = ?;", -1, &updateDoc_, NULL);
    sqlite3_prepare(db_, "SELECT title FROM documents WHERE id = ?;", -1, &getTitle_, NULL);
    sqlite3_prepare(db_, "SELECT body FROM documents WHERE id = ?;", -1, &getBody_, NULL);
    sqlite3_prepare(db_, "SELECT body FROM documents WHERE id = ?;", -1, &getBody_, NULL);
    sqlite3_prepare(db_, "SELECT COUNT(*) FROM documents;", -1, &getDocCount_, NULL);

    return 0;
}

int DocManager::GetDocID(std::string &title)
{
    sqlite3_stmt *st = getDocID_;
    sqlite3_reset(st);
    sqlite3_bind_text(st, 1, title.c_str(), title.size(), SQLITE_STATIC);

    int ret = sqlite3_step(st);
    if (ret == SQLITE_ROW) {
        return sqlite3_column_int(st, 0);
    } else {
        return 0;
    }
}

std::string DocManager::GetTitle(int docID)
{
    std::string title;
    sqlite3_stmt *st = getTitle_;

    sqlite3_reset(st);
    sqlite3_bind_int(st, 1, docID);

    int ret = sqlite3_step(st);
    if (ret == SQLITE_ROW) {
        title = reinterpret_cast<const char *>(sqlite3_column_text(st, 0));
    }
    return title;
}

std::string DocManager::GetBody(int docID)
{
    std::string body;
    sqlite3_stmt *st = getBody_;

    sqlite3_reset(st);
    sqlite3_bind_int(st, 1, docID);

    int ret = sqlite3_step(st);
    if (ret == SQLITE_ROW) {
        body = reinterpret_cast<const char *>(sqlite3_column_text(st, 0));
    }
    return body;
}

int DocManager::WriteDoc(std::string &title, std::string &body)
{
    sqlite3_stmt *st = nullptr;
    int docID = GetDocID(title);

    if (docID == 0) {
        // insert (title, doc)
        st = insertDoc_;
        sqlite3_reset(st);
        sqlite3_bind_text(st, 1, title.c_str(), title.size(), SQLITE_STATIC);
        sqlite3_bind_text(st, 2, body.c_str(), body.size(), SQLITE_STATIC);
    } else {
        // update (title, doc)
        st = updateDoc_;
        sqlite3_reset(st);
        sqlite3_bind_text(st, 1, body.c_str(), body.size(), SQLITE_STATIC);
        sqlite3_bind_int(st, 2, docID);
    }

    int ret = sqlite3_step(st);
    if (ret != SQLITE_DONE) {
        std::cout << "write doc " << title << " fail: " << sqlite3_errmsg(db_) << "\n";
        return -1;
    }

    return 0;
}

int DocManager::GetDocCount()
{
    sqlite3_stmt *st = getDocCount_;

    sqlite3_reset(st);
    int ret = sqlite3_step(st);
    if (ret == SQLITE_ROW) {
        return sqlite3_column_int(st, 0);
    } else {
        std::cout << "get doc count fail\n";
        return -1;
    }
}
